/*
 * Canvas.cpp
 *
 *	Author: stravant
 *	Description:
 *		
 */

#include "Canvas.h"
#include <cmath>

namespace tbt {
namespace fx {

Color& Color::setHSL(double h, double s, double l, double a) {
	double v = (l <= 0.5) ? (l*(1.0+s)) : (l + s - l*s);
	if (v > 0) {
		double m = l+l - v;
		double sv = (v-m)/v;
		h *= 6;
		int sextant = (int)h;
		double fract = h-sextant;
		double vsf = v*sv*fract;
		double mid1 = m+vsf,
			   mid2 = v-vsf;
		//
		switch (sextant) {
		case 0: return set(v, mid1, m);
		case 1: return set(mid2, v, m);
		case 2: return set(m, v, mid1);
		case 3: return set(m, mid2, v);
		case 4: return set(mid1, m, v);
		case 5:
		case 6: //edge case for h = 1.0
			return set(v, m, mid2);
		}
	} else {
		//std::cout << "set(l,l,l), l = " << l << " | R:" << R << " G:" << G << " B:" << B << "\n";
		return set(l, l, l);
	}
	return *this;
}

void Color::toHSL(double& h, double& s, double& l) const {
	h = s = l = 0;
	double v;
	v = std::max(R, G); //1 / 1
	v = std::max(v, B);
	double m;
	m = std::min(R, G); //0 / 0.01
	m = std::min(m, B);
	l = (m+v)/2.0; //l := 0.5 / 0.505
	//
	if (l <= 0.0)
		return;
	//
	double vm = v-m; //1 / 0.99
	s = vm;
	if (s > 0.0) {
		s /= ((l <= 0.5) ? (v+m) : (2.0-v-m)); //
	} else {
		return;
	}
	double r2 = (v-R)/vm,
			g2 = (v-G)/vm,
			b2 = (v-B)/vm;
	if (R == v) {
		h = ((G-B)/vm + ((G<B) ? 6 : 0));
	} else if (G == v) {
		h = ((B == m) ? (1.0+r2) : (3.0-b2));
	} else {
		h = ((R == m) ? (3.0+g2) : (5.0-r2));
	}
	h /= 6.0;
}

void Color::lighten(double amount) {
	double h, s, l;
	toHSL(h, s, l);
	l = std::min(1.0, l+amount);
	setHSL(h, s, l);
}

void Color::darken(double amount) {
	double h, s, l;
	toHSL(h, s, l);
	l = std::max(0.0, l-amount);
	setHSL(h, s, l);
}

void Color::invert() {
	R = 1.0-R;
	G = 1.0-G;
	B = 1.0-B;
}

Color Color::darker(double amount) const {
	double h, s, l;
	toHSL(h, s, l);
	return Color::FromHSL(h, s, std::max(0.0, l-amount));
}

Color Color::lighter(double amount) const {
	double h, s, l;
	toHSL(h, s, l);
	return Color::FromHSL(h, s, std::min(1.0, l+amount));
}

Color Color::inverse() const {
	return Color(1.0-R, 1.0-G, 1.0-B);
}

const Color Color::Red(1.0, 0.0, 0.0);
const Color Color::Green(0.0, 1.0, 0.0);
const Color Color::Blue(0.0, 0.0, 1.0);
const Color Color::Cyan(0.0, 1.0, 1.0);
const Color Color::Magenta(1.0, 0.0, 1.0);
const Color Color::Yellow(1.0, 1.0, 0.0);
const Color Color::Black(0.0, 0.0, 0.0);
const Color Color::White(1.0, 1.0, 1.0);

std::ostream& operator<<(std::ostream& out, const Color& c) {
	out << "Color<" << c.r() << ", " << c.g() << ", " << c.b() << ">";
	return out;
}

}
}















